using UnityEngine;

public class MultiplayerMatchController : MatchController, GGNetworkDeserializer, DisconnectHandlerDelegate
{
	private StandardDeserializer standardDeserializer = new StandardDeserializer();

	protected DisconnectHandler disconnectHandler;

	protected float timeTillRacketUpdate;

	protected float racketUpdateDelay = 1f / 15f;

	protected MRemotePosInfo lastReceivedRacketPos;

	protected float serveDuration;

	private RematchStatus myRematchStatus = RematchStatus.Unknown;

	private RematchStatus opponentRematchStatus = RematchStatus.Unknown;

	protected float realTimeWhenMatchStarted;

	protected bool receivedInitialGameSync;

	protected bool startedGame;

	private float timeBeforeSendSync;

	protected GGNetwork network
	{
		get
		{
			return GGNetwork.instance;
		}
	}

	protected RemotePlayer remote
	{
		get
		{
			return players[1] as RemotePlayer;
		}
	}

	protected HumanPlayer human
	{
		get
		{
			return players[0] as HumanPlayer;
		}
	}

	private PlayerBase servingPlayer
	{
		get
		{
			foreach (PlayerBase player in players)
			{
				if (player.isInServe)
				{
					return player;
				}
			}
			return null;
		}
	}

	public override void Init(GameStartScript starter, MatchUI ui, SingleTableTennis gameType)
	{
		base.starter = starter;
		base.gameType = gameType;
		lastReceivedRacketPos.playerThatHitBall = -1;
		disconnectHandler = starter.CreateGameObject<DisconnectHandler>();
		disconnectHandler.Init(this, MatchParameters.InitParameters.multiplayerParams.supportRoomNameGUID);
		ui.onStartServer = disconnectHandler.ReconnectToServer;
		ui.onStopServer = disconnectHandler.StopServer;
		base.ball = starter.CreateBall();
		base.ball.onCollision = OnBallHitObject;
		base.ball.TakeBall();
		base.ui = ui;
		gameType.Init(this, ui, MatchParameters.InitParameters.pointsToWinGame, MatchParameters.InitParameters.gamesToWinMatch);
		CreatePlayers();
		realTimeWhenMatchStarted = Time.realtimeSinceStartup;
	}

	bool DisconnectHandlerDelegate.isGameRunning()
	{
		return !base.gameDone;
	}

	void DisconnectHandlerDelegate.OnGameShouldFinishBecauseOfDisconnect(bool currentPlayerForfeited, string msg)
	{
		OnGameWon(!currentPlayerForfeited);
	}

	void DisconnectHandlerDelegate.OnDisconnect()
	{
		if (!GGSupportMenu.instance.isNetworkConnected())
		{
			base.gameDone = true;
			NavigationManager.instance.Pop(true);
			OnGameWon(false);
		}
		else
		{
			RemoveBallFromGame();
		}
	}

	void DisconnectHandlerDelegate.OnReconnect(bool currentPlayerWasWaiting)
	{
		if (currentPlayerWasWaiting)
		{
			Debug.Log("Returning to Both Connected");
			base.gameType.ToGameScoreSync(default(AwardPointParams)).Send(network);
			StartServe(base.gameType.servingPlayer);
		}
	}

	void DisconnectHandlerDelegate.UpdateWaitingTime(float timeRemaining)
	{
		base.ui.disconnectLabel.Show(timeRemaining);
	}

	void DisconnectHandlerDelegate.StopShowingWaitingTime()
	{
		base.ui.disconnectLabel.Hide();
	}

	public override void StartGame()
	{
		MatchParameters.MatchParams.MultiplayerParams multiplayerParams = MatchParameters.InitParameters.multiplayerParams;
		Debug.Log("Active Tag " + multiplayerParams.activeTag);
		base.gameType.SetServingPlayer(GetPlayer(multiplayerParams.activeTag));
		if (multiplayerParams.activeTag == 0)
		{
			base.gameType.StartMatch(multiplayerParams.activeTag);
		}
	}

	private void OnEnable()
	{
		network.onMessageReceived += OnNetworkEvent;
	}

	private void OnDisable()
	{
		network.onMessageReceived -= OnNetworkEvent;
	}

	private void OnNetworkEvent(GGNetwork network)
	{
		while (network.HasData())
		{
			network.PollMessage(this);
		}
	}

	void GGNetworkDeserializer.Deserialize(int type, GGNetwork network)
	{
		switch (type)
		{
		case 8:
		{
			MRemotePosInfo racketPos = default(MRemotePosInfo);
			racketPos.Deserialize(network);
			OnRemoteRacketPos(racketPos);
			break;
		}
		case 7:
		{
			MHitBall hitBall = default(MHitBall);
			hitBall.Deserialize(network);
			OnRemoteHitBall(hitBall);
			break;
		}
		case 9:
		{
			MGameScoreSync syncMsg = default(MGameScoreSync);
			syncMsg.Deserialize(network);
			OnRemoteSync(syncMsg);
			break;
		}
		case 10:
			OnRemoteStartServe();
			break;
		case 11:
			OnRemoteStartServeReceived();
			break;
		case 12:
			Debug.Log("Received GGNetworkMessageType.InitGameSync");
			if (!receivedInitialGameSync)
			{
				network.Send(12, true, 0);
			}
			receivedInitialGameSync = true;
			break;
		case 6:
		{
			Debug.Log("Remote player has sent a message");
			MPresetMessage msg = default(MPresetMessage);
			msg.Deserialize(network);
			OnRemotePresetMessage(msg);
			break;
		}
		case 2:
		{
			Debug.Log("Remote player wants a rematch");
			MRematchAccept ra = default(MRematchAccept);
			ra.Deserialize(network);
			OnOpponentAcceptRematch(ra);
			break;
		}
		case 3:
			Debug.Log("Remote player declined a rematch");
			OnOpponentDeclineRematch();
			break;
		case 4:
		case 5:
			break;
		}
	}

	public static Vector3 RemoteToLocalPos(Vector3 remotePos)
	{
		remotePos.z *= -1f;
		remotePos.x *= -1f;
		return remotePos;
	}

	public new void CreatePlayers()
	{
		HumanPlayer humanPlayer = starter.CreateHumanPlayer();
		humanPlayer.Init(players.Count, -1, this);
		players.Add(humanPlayer);
		RemotePlayer remotePlayer = starter.CreateRemotePlayer();
		remotePlayer.Init(players.Count, 1, this);
		players.Add(remotePlayer);
	}

	private int TagForPlayer(PlayerBase player)
	{
		if (player == null)
		{
			return -1;
		}
		return player.teamTag;
	}

	private PlayerBase PlayerFromRemoteTag(int remoteTag)
	{
		if (remoteTag < 0)
		{
			return null;
		}
		return Other(players[remoteTag]);
	}

	private void RemoveBallFromGame()
	{
		foreach (PlayerBase player in players)
		{
			player.BallRemovedFromGame();
		}
		base.ball.isBallInGame = false;
		base.ball.flightPlan.Stop();
		base.ball.MakeKinematic();
		base.ball.position = Vector3.zero;
	}

	private void Update()
	{
		if (NavigationManager.instance.shouldGoBack)
		{
			network.StopServer();
			BehaviourSingleton<ScreenNavigation>.instance.LoadMain(MenuParameters.MenuParams.ShowScreen.Multiplayer);
			return;
		}
		if (network.HasData())
		{
			network.PollMessage(this);
		}
		if (base.gameDone || !disconnectHandler.isConnectionOk)
		{
			return;
		}
		if (!startedGame)
		{
			timeBeforeSendSync -= Time.deltaTime;
			if (timeBeforeSendSync <= 0f)
			{
				timeBeforeSendSync = 1f;
				network.Send(12, true, 0);
				Debug.Log("Sending Init Game Sync");
			}
			if (receivedInitialGameSync)
			{
				startedGame = true;
				StartGame();
			}
			return;
		}
		timeTillRacketUpdate -= Time.deltaTime;
		if (timeTillRacketUpdate < 0f)
		{
			timeTillRacketUpdate = racketUpdateDelay;
			MRemotePosInfo mRemotePosInfo = default(MRemotePosInfo);
			mRemotePosInfo.playerPosition = human.racketPos;
			mRemotePosInfo.ballPos = base.ball.position;
			mRemotePosInfo.ballFlightTime = base.ball.flightPlan.flightTime;
			mRemotePosInfo.pingTime = PhotonNetwork.GetPing();
			mRemotePosInfo.playerThatHitBall = TagForPlayer(base.ball.flightPlan.playerThatHitBall);
			mRemotePosInfo.realTime = Time.realtimeSinceStartup;
			mRemotePosInfo.Send(GGNetwork.instance);
		}
		if (servingPlayer != null)
		{
			serveDuration += Time.deltaTime;
			float num = 15f;
			if (servingPlayer == human && serveDuration >= num)
			{
				RemoveBallFromGame();
				base.gameType.OnTimeOut();
			}
		}
		else
		{
			base.ui.HideServeTime();
		}
	}

	public override void OnPlayerHitBall(PlayerBase player, HitBallParams hitBallParams)
	{
		Debug.Log("OnPlayerHitBall");
		base.gameType.OnPlayerHitBall(player);
		if (player == human)
		{
			Debug.Log("OnPlayerHitBall HUMAN");
			MHitBall mHitBall = default(MHitBall);
			mHitBall.SetFromHitBallParams(hitBallParams);
			mHitBall.isBallInGame = base.ball.isBallInGame;
			mHitBall.Send(network);
			if (base.ball.flightPlan.reboundStage != null)
			{
				float durationTillStage = base.ball.flightPlan.GetDurationTillStage(base.ball.flightPlan.reboundStage);
				int num = PhotonNetwork.GetPing();
				if (lastReceivedRacketPos.pingTime > 50)
				{
					num = num + lastReceivedRacketPos.pingTime - 50;
				}
				float timeScale = durationTillStage / (durationTillStage + (float)num * 0.001f / Time.timeScale);
				base.ball.flightPlan.timeScale = timeScale;
			}
		}
		Other(player).ReceiveBall(base.ball);
	}

	public override void OnBallHitObject(Vector3 pos, HitObjectTag hitObjectTag)
	{
		Debug.Log("OnBallHitObject");
		if (base.ball.flightPlan.playerThatHitBall == remote)
		{
			Debug.Log("OnBallHitObject REMOTE");
			base.gameType.OnBallHitObject(pos, hitObjectTag);
		}
	}

	public override void StartServe(PlayerBase player)
	{
		Debug.Log("StartServe " + (player == human));
		base.ball.isBallInGame = false;
		if (player == human)
		{
			network.Send(10, true, 0);
		}
	}

	public override void AwardPoint(AwardPointParams awardPointParams)
	{
		MGameScoreSync mGameScoreSync = base.gameType.ToGameScoreSync(awardPointParams);
		Debug.Log("AwardPoint " + mGameScoreSync.servingPlayerTag);
		mGameScoreSync.Send(network);
		base.gameType.ContinueFromLastPoint(awardPointParams);
	}

	private void OnRemoteStartServeReceived()
	{
		Debug.Log("OnRemoteStartServeReceived");
		base.StartServe(human);
		serveDuration = 0f;
	}

	private void OnRemoteStartServe()
	{
		Debug.Log("OnRemoteStartServe");
		base.StartServe(remote);
		network.Send(11, true, 0);
		serveDuration = 0f;
	}

	private int RemoteToLocalPlayerTag(int playerTag)
	{
		return (playerTag + 1) % players.Count;
	}

	private void OnRemoteSync(MGameScoreSync syncMsg)
	{
		Debug.Log("OnRemoteSync");
		base.ball.isBallInGame = false;
		syncMsg.servingPlayerTag = RemoteToLocalPlayerTag(syncMsg.servingPlayerTag);
		base.gameType.SyncGameScore(syncMsg);
		AwardPointParams lastPoint = default(AwardPointParams);
		lastPoint.isSetWon = syncMsg.isSetWon;
		lastPoint.isTimeOut = syncMsg.isTimeOut;
		if (syncMsg.playerTagThatWonPoint >= 0)
		{
			lastPoint.playerThatWonPoint = players[(syncMsg.playerTagThatWonPoint + 1) % players.Count];
		}
		base.gameType.ContinueFromLastPoint(lastPoint);
	}

	private void OnRemoteRacketPos(MRemotePosInfo racketPos)
	{
		lastReceivedRacketPos = racketPos;
		remote.SetPosition(racketPos);
	}

	private void OnRemoteHitBall(MHitBall hitBall)
	{
		Debug.Log("OnRemoteHitBall");
		hitBall.ConvertFromRemoteToLocalSpace();
		base.ball.isBallInGame = hitBall.isBallInGame;
		remote.HitBall(base.ball, hitBall);
		int ping = PhotonNetwork.GetPing();
		Debug.Log("PING TIME: " + ping);
		Debug.Log("Remote PING TIME " + hitBall.pingTimeMs);
		if (base.ball.flightPlan.reboundStage != null && Time.timeScale > 0f)
		{
			float durationTillStage = base.ball.flightPlan.GetDurationTillStage(base.ball.flightPlan.reboundStage);
			int num = Mathf.Min(ping, 50);
			float num2 = 1f + (float)num * 0.001f / Time.timeScale / durationTillStage;
			Debug.Log("Desired Scale: " + num2);
			base.ball.flightPlan.timeScale = num2;
		}
		else
		{
			base.ball.flightPlan.timeScale = 1f;
		}
	}

	private void OnGameWonComplete()
	{
		myRematchStatus = RematchStatus.Declined;
		network.Send(3, true, 0);
		GGNetwork.instance.StopServer();
		Time.timeScale = 1f;
		BehaviourSingleton<ScreenNavigation>.instance.LoadMain(MenuParameters.MenuParams.ShowScreen.Multiplayer);
	}

	private void SetUpRematchButtons(bool isPlayerWinner)
	{
		MultiplayerRooms.RoomInfo roomInfo = MultiplayerRooms.instance.FindRoomByType(MatchParameters.InitParameters.multiplayerParams.roomType);
		int num = MatchParameters.InitParameters.multiplayerParams.opponentCoins + ((!isPlayerWinner) ? roomInfo.prize : (-roomInfo.fee));
		if (network.ConnectedPlayers() < 1)
		{
			base.ui.gameDone.DisableButtons();
			return;
		}
		int num2 = GGPlayerSettings.instance.walletManager.CurrencyCount(MultiplayerRooms.instance.multiplayerCurrencyType);
		if (num < roomInfo.fee || num2 < roomInfo.fee)
		{
			base.ui.gameDone.DisableRematchOnly();
		}
		else
		{
			base.ui.gameDone.UpdateButtons(opponentRematchStatus);
		}
	}

	public override void OnGameWon(bool isPlayerWinner)
	{
		base.gameDone = true;
		GGPlayerSettings instance = GGPlayerSettings.instance;
		float num = (isPlayerWinner ? 1 : 0);
		if (isPlayerWinner)
		{
			instance.Model.multiplayerWins++;
			instance.Model.multiplayerLoses--;
		}
		int num2 = 0;
		float num3 = 0f;
		string empty = string.Empty;
		if (isPlayerWinner)
		{
			num2 = MultiplayerRooms.instance.FindRoomByType(MatchParameters.InitParameters.multiplayerParams.roomType).prize;
			num3 = MultiplayerRooms.instance.FindRoomByType(MatchParameters.InitParameters.multiplayerParams.roomType).score;
			empty = "You Won!";
		}
		else
		{
			empty = "You Lost";
		}
		float num4 = instance.LevelProgress();
		int num5 = instance.Level();
		string l = instance.LevelName();
		instance.walletManager.AddCurrency(CurrencyType.coins, num2);
		instance.Save();
		if (num4 < (float)instance.Level())
		{
			Analytics.instance.PlayerReachedNewLevel();
		}
		float curLevel = instance.LevelProgress();
		string l2 = instance.LevelName();
		Analytics.instance.ReportMultiplayerMatchEnd(MatchParameters.InitParameters.multiplayerParams.roomType.ToString());
		MenuParameters.InitParameters.multiplayerPush = true;
		MultiplayerGameDone.GameParams gameParams = MultiplayerGameDone.GameParams.FromMatchParameters().SetWinnerIndex((!isPlayerWinner) ? 1 : 0).SetWinnings(num2)
			.SetLevels(num4, curLevel)
			.SetLevelNames(l, l2)
			.SetPlayerLevels(num5.ToString(), MatchParameters.InitParameters.multiplayerParams.opponentLevel.ToString());
		gameParams.HidePlayerStars();
		SetUpRematchButtons(isPlayerWinner);
		Debug.Log("BEFORE ACHIVEMENT");
		Debug.Log("SHOW ANIM");
		base.ui.gameDone.ShowAnim(gameParams.SetDelegate(delegate
		{
			Debug.Log("Done");
			OnGameWonComplete();
		}));
		float numSeconds = Time.realtimeSinceStartup - realTimeWhenMatchStarted;
		Analytics.instance.ReportMultiplayerDuration(MatchParameters.InitParameters.multiplayerParams.roomType.ToString(), numSeconds);
	}

	private void OnOpponentAcceptRematch(MRematchAccept ra)
	{
		MatchParameters.InitParameters.multiplayerParams.opponentLevel = ra.opponentLevel;
		MatchParameters.InitParameters.multiplayerParams.opponentCoins = ra.coins;
		MatchParameters.InitParameters.multiplayerParams.eloRank = ra.eloRank;
		opponentRematchStatus = RematchStatus.Accepted;
		if (myRematchStatus == RematchStatus.Accepted)
		{
			Analytics.instance.ReportMultiplayerRematch(MatchParameters.InitParameters.multiplayerParams.roomType.ToString(), true);
			if (MatchParameters.InitParameters.multiplayerParams.intro.version > 6)
			{
				MatchParameters.InitParameters.initPlayerTag = ((MatchParameters.InitParameters.initPlayerTag == 0) ? 1 : 0);
			}
			BehaviourSingleton<ScreenNavigation>.instance.LoadMatch(MatchParameters.InitParameters);
		}
		else if (myRematchStatus == RematchStatus.Unknown)
		{
			Analytics.instance.ReportMultiplayerRematch(MatchParameters.InitParameters.multiplayerParams.roomType.ToString(), false);
			base.ui.UpdateRematchButton(opponentRematchStatus);
		}
	}

	private void OnOpponentDeclineRematch()
	{
		opponentRematchStatus = RematchStatus.Declined;
		base.ui.UpdateRematchButton(opponentRematchStatus);
	}

	public void SendPresetMessage(string message)
	{
		Debug.Log("SendingMessage");
		MPresetMessage mPresetMessage = default(MPresetMessage);
		mPresetMessage.msg = message;
		MPresetMessage mPresetMessage2 = mPresetMessage;
		mPresetMessage2.Send(network, 1);
		if (base.gameDone)
		{
			base.ui.RematchMessageToOpponent(message);
		}
		else
		{
			base.ui.MessageToOpponent(message);
		}
	}

	public void onRematch(bool success)
	{
		if (success)
		{
			SendRematchRequest();
		}
		else
		{
			OnGameWonComplete();
		}
	}

	private void SendRematchRequest()
	{
		int coins = GGPlayerSettings.instance.walletManager.CurrencyCount(MultiplayerRooms.instance.multiplayerCurrencyType);
		MRematchAccept mRematchAccept = default(MRematchAccept);
		mRematchAccept.opponentLevel = GGPlayerSettings.instance.Level();
		mRematchAccept.coins = coins;
		mRematchAccept.eloRank = GGPlayerSettings.instance.GetEloRating();
		MRematchAccept mRematchAccept2 = mRematchAccept;
		mRematchAccept2.Send(network);
		myRematchStatus = RematchStatus.Accepted;
		if (opponentRematchStatus == RematchStatus.Accepted)
		{
			Analytics.instance.ReportMultiplayerRematch(MatchParameters.InitParameters.multiplayerParams.roomType.ToString(), true);
			if (MatchParameters.InitParameters.multiplayerParams.intro.version > 6)
			{
				MatchParameters.InitParameters.initPlayerTag = ((MatchParameters.InitParameters.initPlayerTag == 0) ? 1 : 0);
			}
			BehaviourSingleton<ScreenNavigation>.instance.LoadMatch(MatchParameters.InitParameters);
		}
		else if (opponentRematchStatus == RematchStatus.Unknown)
		{
			Analytics.instance.ReportMultiplayerRematch(MatchParameters.InitParameters.multiplayerParams.roomType.ToString(), false);
			base.ui.RematchSent();
		}
	}

	public bool HasOpponentDeclinedRematch()
	{
		return opponentRematchStatus == RematchStatus.Declined;
	}

	private void OnRemotePresetMessage(MPresetMessage msg)
	{
		Debug.Log("Remote sent a message");
		if (base.gameDone)
		{
			base.ui.RematchMessageFromOpponent(msg.msg);
		}
		else
		{
			base.ui.MessageFromOpponent(msg.msg);
		}
	}

	public override void MatchInterfaceOnPause()
	{
	}

	public override void MatchInterfaceOnResume(bool exit)
	{
		OnGameWonComplete();
	}

	public override void MatchInterfaceOnSendMessage(string message)
	{
		SendPresetMessage(message);
	}

	public override void MatchInterfaceOnRematch()
	{
		onRematch(!HasOpponentDeclinedRematch());
	}
}
